/**
 * @file connect_utility.h
 *
 * @author Federico Consoli
 *
 * Released under GNU GPLv3 (http://www.gnu.org/licenses/gpl-3.0.txt)
 */

#ifndef CONNECT_UTILITY_H
#define	CONNECT_UTILITY_H

// Max Size of the string 
#define BUFFERSIZE 500
// Max Size of the buffer to recv and send 
#define BUFF_TO_SEND 300

#include <cstring>
#include <sstream>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <vector>
#include <fstream>
#include <stdio.h>
#include <cstdlib>
#include <errno.h>
#include <pthread.h>
#include <dirent.h>
#include <sys/stat.h>
using namespace std;

/** 
 * Implementation of Connection class.
 * This class contains some metods to send and receive value
 * throught socket, start and close connection, load and save file from/to
 * buffer, delete file and generate random string.
 *
 */
class Connection {
    /**
     * Template class function to send different 
     * kind of number (int,short,unsigned, double...)
     * @param numero Number
     * @param sd socket descriptor
     * @return 0
     */
    template <class T>
    static int invia(T, int);


    /**
     * Template class function to receive different 
     * kind of number (int,short,unsigned, double...)
     * @param numero Number
     * @param sd socket descriptor
     * @return 0 if success else -1
     */
    template <class K>
    static int ricevi(K &, int);

public:

    /**
     * Send "ok"
     * @param sd socket descriptor
     * @return 0
     */
    static int send_ok(int);

    /**
     * Recv "ok"
     * @param  sd socket descriptor
     * @return 0 if receive "ok" else 1
     */
    static int recv_ok(int);

    /**
     * Send a string
     * @param stringa String to send
     * @param sd socket descriptor
     * @return 0 if send string else -1
     */
    static int send_s(string, int);

    /**
     * Receive a string
     * @param stringa String to receive
     * @param sd socket descriptor
     * @return 0 if receive string else -1
     */
    static int recv_s(string&, int);

    /**
     * Send an int number
     * @param numero Number to send
     * @param sd socket descriptor
     * @return @link Connection::invia @endlink return  value
     */
    static int send_int(int, int);

    /**
     * Send a unsigned short number
     * @param numero Number to send
     * @param sd socket descriptor
     * @return @link Connection::invia @endlink return  value
     */
    static int send_short(unsigned short, int);

    /**
     * Receive a unsigned short
     * @param numero Number to receive
     * @param sd socket descriptor
     * @return @link Connection::ricevi @endlink return  value
     */
    static int recv_short(unsigned short&, int);

    /**
     * Send a size_t number
     * @param numero Number to send
     * @param sd socket descriptor
     * @return @link Connection::invia @endlink return  value
     */
    static int send_size_t(size_t, int);

    /**
     * Receive a size_t number
     * @param numero Number to receive
     * @param sd socket descriptor
     * @return @link Connection::ricevi @endlink return  value
     */
    static int recv_size_t(size_t&, int);

    /**
     * Receive a int number
     * @param numero Number to receive
     * @param sd socket descriptor
     * @return @link Connection::ricevi @endlink return  value
     */
    static int recv_int(int&, int);

    /**
     * Send a double number
     * @param numero Number to send
     * @param sd socket descriptor
     * @return @link Connection::invia @endlink return  value
     */
    static int send_double(double, int);

    /**
     * Receive a double number
     * @param numero Number to receive
     * @param sd socket descriptor
     * @return @link Connection::ricevi @endlink return  value
     */
    static int recv_double(double&, int);

    /**
     * Send a big buffer
     * @param long_string Pointer to the buffer
     * @param buf_len Lenght of the buffer
     * @param sd socket descriptor
     * @return 0
     */
    static int send_buff(char*, int, int);

    /**
     * Receive a big buffer
     * @param long_string Pointer to the buffer
     * @param len Lenght of the buffer
     * @param sd socket descriptor
     * @return 0
     */
    static int recv_buff(char*&, int&, int);

    /**
     * Open a connection to the ip, port
     * @param ip ip to connect
     * @param porta port to connect
     * @return socket descriptor
     */
    static int connect_to(string, short);

    /**
     * Close socket
     * @param sd socket descriptor
     * @return 1 if success else 0
     */
    static int close_sock(int);

    /**
     * Listen for incoming connetion from ip and port
     * @param ip ip to listen for
     * @param porta port to listen for
     * @return socket descriptor
     */
    static int listen_for(string, short);

    /**
     * Open a file and put it in a buffer
     * @param memblock pointer to the memory block where put the file
     * @param filename name of the file to open
     * @param len reference lenght of the memblock
     * @return 0 if success else -1
     */
    static int file_to_string(char*&, string, int&);

    /**
     * Save a buffer in a file
     * @param buffer pointer buffer to save
     * @param filename name of the file where to save
     * @param len lenght of the buffer to save
     * @return  0 if success else -1
     */
    static int string_to_file(char*, string, int);

    /**
     * Generate a random string
     * @param random random String generate
     * @return 0
     */
    static int random_string(string&);

    /**
     * Delete a file
     * @param name name of the file to delete
     * @return 0 if success else -1
     */
    static int remove_file(string);
    
    /**
     * Return a string taking a char *
     * @param elem pointer to char
     * @return string
     */
    static string char_to_string(const char *);
    /**
     * Return a unsigned short from a char*
     * @param elem pointer to char
     * @return unsigned short
     */
    static unsigned short char_to_uns_short(const char *);
};

#endif	/* CONNECT_UTILITY_H */

